/**
 * 20220121：finalized by jordia
 */
import Vec3 from "../../common/vec3";
import CONSTANT from "../../constant";
import EpaTriangle from "./epa-triangle";
import Method from "../../common/method";

/**
 * 扩展多边形
 */
export default class EpaPolyhedron {
    constructor() {
        this._vertices = new Array(CONSTANT.SETTING_MAX_EPA_VERTICES);
        this._center = new Vec3();
        this._numVertices = 0;
        this._triangleList = null;
        this._triangleListLast = null;
        this._numTriangles = 0;
        this._trianglePool = null;
        this._vertexPool = null;
        this._status=null;
    }
    dumpHoleEdge(first) {
    }
    validate() {
        let t = this._triangleList;
        let tv=t._vertices,tai=t._adjacentPairIndex,tat=t._adjacentTriangles;
        while(t != null) {
            tv[0]._tmpEdgeLoopOuterTriangle = null;
            tv[0]._tmpEdgeLoopNext = null;
            if(tai[0] === -1) {
                this._status = 2;
                return false;
            }
            if(tat[0] == null) {
                this._status = 3;
                return false;
            }
            tv[1]._tmpEdgeLoopOuterTriangle = null;
            tv[1]._tmpEdgeLoopNext = null;
            if(tai[1] === -1) {
                this._status = 2;
                return false;
            }
            if(tat[1] == null) {
                this._status = 3;
                return false;
            }
            tv[2]._tmpEdgeLoopOuterTriangle = null;
            tv[2]._tmpEdgeLoopNext = null;
            if(tai[2] === -1) {
                this._status = 2;
                return false;
            }
            if(tat[2] == null) {
                this._status = 3;
                return false;
            }
            t = t._next;
        }
        return true;
    }
    findEdgeLoop(id,base,_from) {
        if(base._tmpDfsId === id) return;
        base._tmpDfsId = id;
        let from=_from.elements;
        let bse = base.tmp.elements, v = base._vertices[0].v.elements, v1 = base._normal.elements;
        Method.copyElements(from,bse,0,0,3);
        Method.subArray(bse,v,bse,0,0,0,3);
        let vis=base._tmpDfsVisible = Method.multiplyArray(bse,v1,0,0,3) > 0;
        if(!vis) {
            this._status = 6;
            return;
        }
        let _g = 0;
        while(_g < 3) {
            let i = _g++;
            let t = base._adjacentTriangles[i];
            if(t == null) continue;
            let tes = t.tmp.elements, v = t._vertices[0].v.elements, v1 = t._normal.elements;
            Method.copyElements(from,tes,0,0,3);
            Method.subArray(tes,v,tes,0,0,0,3);
            vis=t._tmpDfsVisible = Method.multiplyArray(tes,v1,0,0,3) > 0;
            if(vis) {
                this.findEdgeLoop(id,t,_from);
            } else {
                let v1 = base._vertices[i];
                v1._tmpEdgeLoopNext = base._vertices[base._nextIndex[i]];
                v1._tmpEdgeLoopOuterTriangle = t;
            }
        }
        let triangle = base._adjacentTriangles[0];
        if(triangle != null) {
            let pairIndex = base._adjacentPairIndex[0];
            triangle._adjacentTriangles[pairIndex] = null;
            triangle._adjacentPairIndex[pairIndex] = -1;
            base._adjacentTriangles[0] = null;
            base._adjacentPairIndex[0] = -1;
        }
        triangle = base._adjacentTriangles[1];
        if(triangle != null) {
            let pairIndex = base._adjacentPairIndex[1];
            triangle._adjacentTriangles[pairIndex] = null;
            triangle._adjacentPairIndex[pairIndex] = -1;
            base._adjacentTriangles[1] = null;
            base._adjacentPairIndex[1] = -1;
        }
        triangle = base._adjacentTriangles[2];
        if(triangle != null) {
            let pairIndex = base._adjacentPairIndex[2];
            triangle._adjacentTriangles[pairIndex] = null;
            triangle._adjacentPairIndex[pairIndex] = -1;
            base._adjacentTriangles[2] = null;
            base._adjacentPairIndex[2] = -1;
        }
        this._numTriangles--;
        let prev = base._prev, next = base._next;
        if(prev != null) prev._next = next;
        if(next != null) next._prev = prev;
        if(base === this._triangleList) this._triangleList = this._triangleList._next;
        if(base === this._triangleListLast) this._triangleListLast = this._triangleListLast._prev;
        base._next = null;
        base._prev = null;
        base.removeReferences();
        base._next = this._trianglePool;
        this._trianglePool = base;
    }
    _getTriangle(){
        let t = this._trianglePool;
        if(t != null) {
            this._trianglePool = t._next;
            t._next = null;
        } else {
            t = new EpaTriangle();
        }
        return t;
    }
    _setTriangleList(t1){
        this._numTriangles++;
        if(this._triangleList == null) {
            this._triangleList = this._triangleListLast = t1;
        } else {
            this._triangleListLast._next = t1;
            t1._prev = this._triangleListLast;
            this._triangleListLast = t1;
        }
    }
    _init(v1,v2,v3,v4) {
        this._status = 0;
        this._numVertices = 4;
        Method.setXYZW(this._vertices,v1,v2,v3,v4,0);//set 4 children
        let ces = this._center.elements;
        let v = v1.v.elements, v5 = v2.v.elements, v6 = v3.v.elements, v7 = v4.v.elements;
        Method.setXYZ(ces,v[0]+v5[0]+v6[0]+v7[0],v[1]+v5[1]+v6[1]+v7[1],v[2]+v5[2]+v6[2]+v7[2]);
        Method.scaleArray(ces,0.25,ces,0,0,3);
        let t1 = this._getTriangle();
        let t2 = this._getTriangle();
        let t3 = this._getTriangle();
        let t4 = this._getTriangle();
        if(!t1.init(v1,v2,v3,this._center,true)) this._status = 1;
        if(!t2.init(v1,v2,v4,this._center,true)) this._status = 1;
        if(!t3.init(v1,v3,v4,this._center,true)) this._status = 1;
        if(!t4.init(v2,v3,v4,this._center,true)) this._status = 1;
        if(!t1.setAdjacentTriangle(t2)) this._status = 1;
        if(!t1.setAdjacentTriangle(t3)) this._status = 1;
        if(!t1.setAdjacentTriangle(t4)) this._status = 1;
        if(!t2.setAdjacentTriangle(t3)) this._status = 1;
        if(!t2.setAdjacentTriangle(t4)) this._status = 1;
        if(!t3.setAdjacentTriangle(t4)) this._status = 1;
        this._setTriangleList(t1);
        this._setTriangleList(t2);
        this._setTriangleList(t3);
        this._setTriangleList(t4);
        return this._status === 0;
    }
    _addVertex(vertex,base) {
        this._vertices[this._numVertices++] = vertex;
        let v1 = base._vertices[0];
        this.findEdgeLoop(this._numVertices,base,vertex.v);
        if(this._status !== 0) return false;
        let v = v1;
        let prevT = null, firstT = null;
        while(true) {
            if(v._tmpEdgeLoopNext == null) {
                this._dumpAsObjModel();
                this._status = 4;
                return false;
            }
            if(v._tmpEdgeLoopOuterTriangle == null) {
                this._status = 5;
                return false;
            }
            let first = this._trianglePool;
            if(first != null) {
                this._trianglePool = first._next;
                first._next = null;
            } else {
                first = new EpaTriangle();
            }
            let t = first;
            if(firstT == null) firstT = t;
            if(!t.init(v,v._tmpEdgeLoopNext,vertex,this._center,false)) this._status = 1;
            if(this._status !== 0) return false;
            this._setTriangleList(t);
            if(!t.setAdjacentTriangle(v._tmpEdgeLoopOuterTriangle)) this._status = 1;
            if(prevT != null) {
                if(!t.setAdjacentTriangle(prevT)) this._status = 1;
            }
            prevT = t;
            v = v._tmpEdgeLoopNext;
            if(!(v !== v1)) break;
        }
        if(!prevT.setAdjacentTriangle(firstT)) this._status = 1;
        if(this._status === 0) {
            return this.validate();
        } else {
            return false;
        }
    }
    _dumpAsObjModel() {
    }
}